use crate::stack::{Crate, Stack};
use crate::command::Command;

#[derive(Debug)]
pub struct Context {
    stacks: Vec<Stack>,
}

impl Context {
    pub fn execute(&mut self, command: Command) {
        // Fuck you Rust
        let from_stack = &mut self.stacks[command.from_stack_id()];
        let pop_ctrs = (0..command.crate_size())
            .map(|_| from_stack.pop())
            .collect::<Vec<Crate>>();
        
        let to_stack = &mut self.stacks[command.to_stack_id()];

        pop_ctrs
            .into_iter()
            .for_each(|ctr| {
                to_stack.push(ctr)
            });
    }

    pub fn execute_retain_order(&mut self, command: Command) {
        // Fuck you Rust
        let from_stack = &mut self.stacks[command.from_stack_id()];
        let pop_ctrs = (0..command.crate_size())
            .map(|_| from_stack.pop())
            .collect::<Vec<Crate>>();
        
        let to_stack = &mut self.stacks[command.to_stack_id()];

        pop_ctrs
            .into_iter()
            .rev()
            .for_each(|ctr| {
                to_stack.push(ctr)
            });
    }

    pub fn stacks(&self) -> &Vec<Stack> {
        &self.stacks
    }
}

impl From<&str> for  Context {
    fn from(value: &str) -> Self {
        // Get stack id
        let line = value.lines().last().unwrap();
        let stack_ids = line
            .split_whitespace()
            .map(|s| s.parse::<usize>().unwrap())
            .collect::<Vec<usize>>();

        let mut stacks = vec![Stack::new(); stack_ids.len()];

        value
            .lines()
            .into_iter()
            .rev()
            .skip(1)
            .for_each(|line| {
                let chars = line.chars().collect::<Vec<char>>();
                for i in 0..stack_ids.len() {
                    let stack_id = stack_ids[i];
                    let stack = &mut stacks[stack_id - 1];
                    let crt = chars[(i * 4) + 1];
                    if crt != ' ' {
                        stack.push(crt);
                    }
                }
            });

        Self {
            stacks
        }
    }
}